/*******************************************************************************
 * Copyright (c) 2000, 2004 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.testng.eclipse.ui;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.texteditor.ITextEditor;

import org.testng.eclipse.util.JDTUtil;
import org.testng.eclipse.util.ResourceUtil;
/**
 * Open a class on a Test method.
 */
public class OpenTestAction extends OpenEditorAction {

	private String fMethodName;
	private ISourceRange fRange;
	private RunInfo fRunInfo;

	public OpenTestAction(TestRunnerViewPart testRunner, RunInfo runInfo) {
		this(testRunner, runInfo.getClassName(), runInfo.getMethodName(), true);
		fRunInfo = runInfo;
	}

	public OpenTestAction(TestRunnerViewPart testRunner, RunInfo runInfo,
			boolean activate) {
		this(testRunner, runInfo.getClassName(), runInfo.getMethodName(),
				activate);
		fRunInfo = runInfo;
	}

	/**
	 * Constructor for OpenTestAction.
	 */
	//  public OpenTestAction(TestRunnerViewPart testRunner, String className, String method) {
	//    this(testRunner, className, method, true);
	//  }
	public OpenTestAction(TestRunnerViewPart testRunner, String className) {
		this(testRunner, className, null, true);
	}

	public OpenTestAction(TestRunnerViewPart testRunner, String className,
			String method, boolean activate) {
		super(testRunner, className, activate);
		fMethodName = method;
	}

	protected IJavaElement findElement(IJavaProject project, String className)
			throws JavaModelException {
		IJavaElement javaElement = null;
		if (null != fRunInfo) {
			javaElement = JDTUtil.findElement(project, fRunInfo);
		} else {
			javaElement = JDTUtil.findElement(project, className);
		}

		if (null == fMethodName) {
			return javaElement;
		}

		IMethod method = (IMethod) javaElement;

		if (null == method) {
			String title = ResourceUtil.getString("OpenTestAction.error.title"); //$NON-NLS-1$
			String message = ResourceUtil.getFormattedString(
					"OpenTestAction.error.methodNoFound", //$NON-NLS-1$
					fMethodName);
			MessageDialog.openInformation(getShell(), title, message);

			return JDTUtil.findElement(project, className);
		}
		fRange = method.getNameRange();

		return javaElement;
	}

	protected void reveal(ITextEditor textEditor) {
		if (fRange != null) {
			textEditor.selectAndReveal(fRange.getOffset(), fRange.getLength());
		}
	}

	public boolean isEnabled() {
		if (null == getClassName()) {
			// HINT: should never happen now
			return false;
		}

		try {
			return getLaunchedProject().findType(getClassName()) != null;
		} catch (JavaModelException e) {
		}

		return false;
	}

	// This method should be kept out of the main line
	// until the changes described below are integrated.
	public void run() {
		/*
		 * Total hack to enable streambase developers to go directly to xml source 
		 * files when running the internal streambase 'xml tests' in eclipse. It 
		 * depends on the test description being created a specific way and the 
		 * xml source being located in a specific project in the workspace. This
		 * code is highly unlikely to interfere with anyone else's work if it is 
		 * merged into the main branch by accident, but it really does not belong 
		 * there. Once the TestNG core is changed to allow transmitting attributes 
		 * from the instance being tested to the plugin, this section can be replaced
		 * by generic code that could check the runInfo for the filename, project name
		 * for the file, and line number for the file.
		 */
		if (fRunInfo != null
				&& fRunInfo.getTestDescription() != null
				&& fRunInfo.getClassName().equals(
						"com.streambase.sb.runtime.test.XMLTestngTestRunner")) {
			String desc = fRunInfo.getTestDescription();
			desc = desc.substring(1, desc.length() - 1);
			String[] file_location = desc.split(":");

			String filename = file_location[0];
			String lineNumber = file_location[2];
			String project = "xmltests";
			// code above this is the total hack
			// code below this line could be used generically once the 
			// data is available in a standardized way
			IWorkbenchPage page = PlatformUI.getWorkbench()
					.getActiveWorkbenchWindow().getActivePage();
			IFile file = org.eclipse.core.resources.ResourcesPlugin
					.getWorkspace().getRoot().getProject(project).getFile(
							filename);

			try {
				IMarker marker = file.createMarker(IMarker.TEXT);
				Map map = new HashMap();
				map.put(IMarker.LINE_NUMBER, new Integer(lineNumber));
				marker.setAttributes(map);
				IDE.openEditor(page, marker);
				marker.delete();
			} catch (CoreException ce) {
				ce.printStackTrace();
			}

		} else {
			super.run();
		}
	}
}
